#include "qvbox.h"
#include "ui_qvbox.h"

#include <QDebug>
#include <QFile>
#include <QDateTime>
#include <QMessageBox>
#include <QTextBlock>
#include <QTextDocument>
#include <QListView>
#include <QFileDialog>
#include <QTextStream>

#define SendHistoryMaxItem  100

QVBOX::QVBOX(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::QVBOX)
{
    ui->setupUi(this);

    m_SendHistoryGetIndex = 0;

    createActions();
    createMenus();

    //实例化串口
    mySerialPort = new MySerialPort();
    // mySerialPort->setParent(this);

    //创建线程
    m_pSpThread = new QThread(0);
    mySerialPort->moveToThread(m_pSpThread);
    m_pSpThread->start();

    m_QLableTxRx = new QLabel("Tx:0  Rx:0", this);
    ui->statusBar->addPermanentWidget(m_QLableTxRx);

    m_FixSendTimer = new QTimer(this);
    ui->lineEditTime->setPlaceholderText("单位:毫秒");

    ui->pteSendData->installEventFilter(this);//设置完后自动调用其eventFilter函数

    //加载配置文件
    m_setting = new setting(QDir::home().homePath() + "/VboxSetting.ini");

    //读编码配置
    mySerialPort->m_EncodingType = m_setting->Get("EncodingType").toInt();
    if (mySerialPort->m_EncodingType == ENCODING_TYPE_GBK)
        m_ActEncodingGbk->setChecked(true);
    else
        m_ActEncodingUtf8->setChecked(true);

    //读时间戳配置
    mySerialPort->m_NeedTimeStamp = m_setting->Get("NeedTimeStamp").toBool();
    ui->checkTimeStamp->setChecked(mySerialPort->m_NeedTimeStamp);

    //读发送回车换行配置
    mySerialPort->m_NewLineFlag = m_setting->Get("NewLineFlag").toBool();
    ui->checkNewLine->setChecked(mySerialPort->m_NewLineFlag);

    //读取保存到文件配置
    ui->checkSaveToFile->setChecked(m_setting->Get("SaveToFile").toBool());


    //处理接收到的数据显示到文本框
    connect(mySerialPort,&MySerialPort::signalSerialPortRecvShow,
            this,&QVBOX::slotSerialPortRecvShow);

    //初始化串口界面相关参数
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        ui->cbxSpName->addItem(info.portName());
    }
    QStringList baudRateList = {"460800","115200","38400","19200","9600","custom"};
    QStringList DataBitList = { "Data 8bit", "Data 7bit", "Data 6bit", "Data 5bit"};
    QStringList StopBitList =  { "Stop 1bit", "Stop 1.5bit", "Stop 2bit"};
    QStringList ParityList = { "NoParity", "EvenParity", "OddParity"};
    ui->cbxBaudRate->addItems(baudRateList);
    ui->cbxDataBit->addItems(DataBitList);
    ui->cbxStopBit->addItems(StopBitList);
    ui->cbxParityBit->addItems(ParityList);

    //启动默认115200
    ui->cbxBaudRate->setCurrentIndex(1);


    //读取发送历史数据
    QFile file(QDir::home().homePath() + "/vboxSendHistory.info");
    if (file.exists() == true)
    {
        if (file.open(QIODevice::ReadOnly) == true)
        {
            QByteArray lineData;
            while(!file.atEnd())
            {
                lineData = file.readLine(0);
                lineData.replace(QByteArray("\n"),QByteArray(""));
                m_SendHistoryList.append(lineData);
            }
        }
    }
    else
        m_SendHistoryList.insert(0,"");

    //设置下拉列表项高度 方便操作
    ui->cbxSendHistory->setView(new QListView());
    ui->cbxSendHistory->setStyleSheet("QComboBox QAbstractItemView::item{height:40px;}");
    ui->cbxSendHistory->addItems(m_SendHistoryList);

    //可自定义串口波特率
    connect(ui->cbxBaudRate, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=](int index){
        index = index;
        if (ui->cbxBaudRate->currentText() == "custom")
        {
            ui->cbxBaudRate->setEditable(true);
            ui->cbxBaudRate->lineEdit()->clear();
        }
        else
            ui->cbxBaudRate->setEditable(false);
    });
    //绑定串口点击按钮动作
    connect(ui->btnOpenClose,&QPushButton::clicked,this,&QVBOX::slotBtnOpenCloseClick);
    //实现串口名称触发检测
    connect(ui->cbxSpName,&MyComboBox::clicked,[=](){
        ui->cbxSpName->clear();
        foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
            ui->cbxSpName->addItem(info.portName());
        }
    });
    //绑定发送按钮
    connect(ui->btnSendData,&QPushButton::clicked, this, &QVBOX::slotBtnSendData);
    //选中存储到文件
    connect(ui->checkSaveToFile,&QCheckBox::clicked,[=](){
        m_setting->Set("SaveToFile", ui->checkSaveToFile->isChecked());
        if (ui->checkSaveToFile->isChecked() == true)
        {
            m_SaveFilePath = QCoreApplication::applicationDirPath()+"/";
            m_SaveFileName = "QVbox"+QDateTime::currentDateTime().toString("yyyy_MM_dd_hh")+".log";
            ui->statusBar->showMessage("save data to file -> "+m_SaveFilePath+m_SaveFileName);
        }
        else
        {
            ui->statusBar->clearMessage();
        }
    });
    //绑定接收清空按钮
    connect(ui->btnClearRecvTextEdit,&QPushButton::clicked,[=](){
        ui->pteShowData->clear();
        mySerialPort->m_TxByteCnt = 0;
        mySerialPort->m_RxByteCnt = 0;
        updateStatusBarTxRx();
    });
    //绑定发送清空按钮
    connect(ui->btnClearSendData,&QPushButton::clicked,[=](){
        ui->pteSendData->clear();
    });
    //绑定接收存储按键
    connect(ui->btnSaveRecvTextEdit,&QPushButton::clicked,[=](){
        QString SaveRecvFilePath = QCoreApplication::applicationDirPath()+"/";
        QString SaveRecvFileName = "QVboxSave"+QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss")+".log";
        QFile file(SaveRecvFilePath+SaveRecvFileName);
        if (file.open(QIODevice::Append) == true)
        {
            QString saveStr = ui->pteShowData->toPlainText();
            //防止内容中有'\0' 会导致保存的文件从'\0'处断开 保存不完整
            saveStr.replace('\0',' ');
            file.write(saveStr.toUtf8().data());
            file.close();
            QMessageBox::information(NULL,"提示","已保存到 "+SaveRecvFilePath+SaveRecvFileName,QMessageBox::Yes);
        }
        else
            QMessageBox::warning(NULL,"提示","保存失败",QMessageBox::Yes);
    });
    //时间戳选项
    connect(ui->checkTimeStamp,&QCheckBox::stateChanged,[=](){
        mySerialPort->m_NeedTimeStamp = ui->checkTimeStamp->isChecked();
        m_setting->Set("NeedTimeStamp", mySerialPort->m_NeedTimeStamp);
    });
    //发送历史选取功能
    connect(ui->cbxSendHistory, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),[=](int index){
        if (index > 0)
            ui->pteSendData->setPlainText(ui->cbxSendHistory->currentText());
    });
    //定时发送选择功能
    connect(ui->checkFixSend,&QCheckBox::clicked,[=](){
        if (ui->checkFixSend->isChecked())
        {
            if (ui->lineEditTime->text() == "")
            {
                QMessageBox::warning(NULL,"提示","定时发送时间错误",QMessageBox::Yes);
                ui->checkFixSend->setChecked(false);
                return;
            }
            ui->lineEditTime->setEnabled(false);
            m_FixSendTimer->start(ui->lineEditTime->text().toInt());
        }
        else
        {
            ui->lineEditTime->setEnabled(true);
            m_FixSendTimer->stop();
        }
    });
    //定时发送定时器超时处理
    connect(m_FixSendTimer,&QTimer::timeout,[=](){
        QByteArray ba = ui->pteSendData->toPlainText().toUtf8();
        if ((this->mySerialPort->spWrite(ba) == 0) && (this->mySerialPort->m_OpenFlag == false))
        {
            m_FixSendTimer->stop();
            ui->checkFixSend->setChecked(false);
            ui->lineEditTime->setEnabled(true);
        }
    });
    connect(ui->checkHexSend,&QCheckBox::clicked,[=](){
        mySerialPort->m_HexSendFlag = ui->checkHexSend->isChecked();
    });
    connect(ui->checkHexShow,&QCheckBox::clicked,[=](){
        mySerialPort->m_HexShowFlag = ui->checkHexShow->isChecked();
    });
    connect(ui->checkNewLine,&QCheckBox::clicked,[=](){
        mySerialPort->m_NewLineFlag = ui->checkNewLine->isChecked();
        m_setting->Set("NewLineFlag", mySerialPort->m_NewLineFlag);
    });
}

QVBOX::~QVBOX()
{
    delete ui;
    m_pSpThread->exit();
    mySerialPort->~MySerialPort();
}

//重写窗口关闭事件
void QVBOX::closeEvent(QCloseEvent *e)
{
    if (ui->checkSaveToFile->isChecked() == true)
    {
        if (QMessageBox::question(this,
                                  tr("Quit"),
                                  tr("正在实时保存数据到文件，确认关闭？"),
                                  QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
        {
            e->ignore();
        }
    }
}

bool QVBOX::eventFilter(QObject *target, QEvent *event)
{
    if(target == ui->pteSendData)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *k = static_cast<QKeyEvent *>(event);
            if(k->key() == Qt::Key_Return)  //回车发送数据
            {
                slotBtnSendData();
                ui->pteSendData->clear();
                return true;
            }
            else if (k->key() == Qt::Key_Up)
            {
                ui->pteSendData->clear();   //调取历史发送数据 上翻
                if (m_SendHistoryGetIndex < ui->cbxSendHistory->count())
                    m_SendHistoryGetIndex++;
                ui->pteSendData->setPlainText(ui->cbxSendHistory->itemText(m_SendHistoryGetIndex));
                ui->pteSendData->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
                return true;
            }
            else if (k->key() == Qt::Key_Down)  //调取历史发送数据 下翻
            {
                ui->pteSendData->clear();
                if (m_SendHistoryGetIndex > 1)
                    m_SendHistoryGetIndex--;
                ui->pteSendData->setPlainText(ui->cbxSendHistory->itemText(m_SendHistoryGetIndex));
                ui->pteSendData->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
                return true;
            }
        }
    }
    return QWidget::eventFilter(target,event);
}


void QVBOX::updateStatusBarTxRx()
{
    QString str;
    str.sprintf("Tx:%llu  Rx:%llu",mySerialPort->m_TxByteCnt, mySerialPort->m_RxByteCnt);
    m_QLableTxRx->setText(str);
}


void QVBOX::slotBtnSendData()
{
    QByteArray ba = ui->pteSendData->toPlainText().toUtf8();
    if (this->mySerialPort->spWrite(ba) == 0)
        return;

    m_SendHistoryGetIndex = 0;
    updateStatusBarTxRx();

    //判断发送数据是否存在 更新发送历史列表
    for (int i = 0 ; i < m_SendHistoryList.length(); i++)
    {
        if (QString::compare(m_SendHistoryList.at(i),ba) == 0)
        {
            //找到重复的数据 删除 然后插入到最新的位置
            if (i <= 1)
                return;
            else
                m_SendHistoryList.removeAt(i);
        }
    }
    m_SendHistoryList.insert(1,ba);
    if (m_SendHistoryList.length() > SendHistoryMaxItem)
        m_SendHistoryList.removeLast();
    ui->cbxSendHistory->clear();
    ui->cbxSendHistory->addItems(m_SendHistoryList);

    //保存发送历史到文件
    QFile file(QDir::home().homePath() + "/vboxSendHistory.info");
    if (file.open(QIODevice::WriteOnly) == true)
    {
        foreach (QString cmd, m_SendHistoryList) {
            file.write(cmd.toUtf8().data());
            file.write("\n");
        }
        file.close();
    }
}

void QVBOX::slotSerialPortRecvShow(QString data)
{
    //显示数据到文本框
    ui->pteShowData->appendPlainText(data);
    updateStatusBarTxRx();

    //保存数据到文件
    if (ui->checkSaveToFile->isChecked() == true)
    {
        QFile file(m_SaveFilePath+m_SaveFileName);
        if (file.open(QIODevice::Append) == true)
        {
            file.write(data.toUtf8()+'\n');//不上串口接收时去掉的\n
            file.close();
        }
    }
}

void QVBOX::slotBtnOpenCloseClick()
{
    if (!mySerialPort->m_OpenFlag)
    {
        mySerialPort->m_SpName = ui->cbxSpName->currentText();
        mySerialPort->m_BaudRate = ui->cbxBaudRate->currentText().toInt();

        if (ui->cbxDataBit->currentText() == "Data 7bit")
            mySerialPort->m_DataBit = QSerialPort::Data7;
        else if (ui->cbxDataBit->currentText() == "Data 6bit")
            mySerialPort->m_DataBit = QSerialPort::Data6;
        else if (ui->cbxDataBit->currentText() == "Data 5bit")
            mySerialPort->m_DataBit = QSerialPort::Data5;
        else
            mySerialPort->m_DataBit = QSerialPort::Data8;

        if (ui->cbxStopBit->currentText() == "Stop 2bit")
            mySerialPort->m_StopBit = QSerialPort::TwoStop;
        else if (ui->cbxStopBit->currentText() == "Stop 1.5bit")
            mySerialPort->m_StopBit = QSerialPort::OneAndHalfStop;
        else
            mySerialPort->m_StopBit = QSerialPort::OneStop;

        if (ui->cbxParityBit->currentText() == "OddParity")
            mySerialPort->m_Parity = QSerialPort::OddParity;
        else if (ui->cbxParityBit->currentText() == "EvenParity")
            mySerialPort->m_Parity = QSerialPort::EvenParity;
        else
            mySerialPort->m_Parity = QSerialPort::NoParity;

        if (mySerialPort->spOpen())
            ui->btnOpenClose->setText("关闭");
        else
             ui->btnOpenClose->setText("打开");
    }
    else
    {
        mySerialPort->spClose();
        ui->btnOpenClose->setText("打开");
    }
}

void QVBOX::createActions()
{
    m_ActNew = new QAction(tr("新建"), this);
    m_ActNew->setShortcuts(QKeySequence::New);
    connect(m_ActNew, &QAction::triggered, [=](){
        qDebug() << "new file";
    });

    m_ActSave = new QAction(tr("另存为"), this);
    m_ActSave->setShortcuts(QKeySequence::Save);
    connect(m_ActSave, &QAction::triggered, [=](){
        QFileDialog fileDialog;
        m_SaveFilePath = QCoreApplication::applicationDirPath()+"/";
        QString fileName = fileDialog.getSaveFileName(this,tr("Open File"),m_SaveFilePath,tr("Text File(*.txt)"));
        if(fileName == "")
        {
            return;
        }
        QFile file(fileName);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QMessageBox::warning(this,tr("错误"),tr("打开文件失败"));
            return;
        }
        else
        {
            QTextStream textStream(&file);
            QString saveStr = ui->pteShowData->toPlainText();
            textStream << saveStr;
            QMessageBox::warning(this,tr("提示"),tr("保存文件成功"));
            file.close();
        }
    });

    m_ActEncodingGbk = new QAction(tr("gbk"), this);
    m_ActEncodingGbk->setCheckable(true);
    connect(m_ActEncodingGbk, &QAction::triggered, [=](){
        mySerialPort->m_EncodingType = ENCODING_TYPE_GBK;
        m_setting->Set("EncodingType", mySerialPort->m_EncodingType);
    });

    m_ActEncodingUtf8 = new QAction(tr("utf8"), this);
    m_ActEncodingUtf8->setCheckable(true);
    connect(m_ActEncodingUtf8, &QAction::triggered, [=](){
        mySerialPort->m_EncodingType = ENCODING_TYPE_UTF8;
        m_setting->Set("EncodingType", mySerialPort->m_EncodingType);
    });

    /* action添加组分类 */
    m_ActGrpEncoding = new QActionGroup(this);
    m_ActGrpEncoding->addAction(m_ActEncodingGbk);
    m_ActGrpEncoding->addAction(m_ActEncodingUtf8);
    m_ActEncodingGbk->setChecked(true);
}

void QVBOX::createMenus()
{
    /* 设置状态栏颜色 */
    this->setStyleSheet("QMenu::item:selected{background-color:#ff0000;}\
                            QMenuBar{background-color:#eeeeee;}");

    /* 创建2个menu */
    m_MenuFile = ui->menuBar->addMenu("文件");
    m_MenuSetting = ui->menuBar->addMenu("设置");

    m_MenuFile->addAction(m_ActNew);
    m_MenuFile->addAction(m_ActSave);

    /* menu中添加menu */
    m_MenuEncoding = m_MenuSetting->addMenu("编码格式");
    m_MenuEncoding->addAction(m_ActEncodingUtf8);
    m_MenuEncoding->addAction(m_ActEncodingGbk);

}

